/**
 * Copyright 2021 Solomon. All rights reserved.
 * Date : 2021.03.24
 */

#include "./inc/spd2010_mgd.h"
#include "./inc/spd2010_mgd_parse.h"

struct _FWPart FW_Part[6];
struct _FWInfo FWInfo;

/*******************************/
/* CharToInt                   */
/*******************************/
unsigned int CharToInt(char data, int mode)
{
    if (mode == 0)
    {
        switch (data)
        {
            case '0':
                return 0;
            case '1':
                return 1;
            case '2':
                return 2;
            case '3':
                return 3;
            case '4':
                return 4;
            case '5':
                return 5;
            case '6':
                return 6;
            case '7':
                return 7;
            case '8':
                return 8;
            case '9':
                return 9;
            case 'A':
            case 'a':
                return 10;
            case 'B':
            case 'b':
                return 11;
            case 'C':
            case 'c':
                return 12;
            case 'D':
            case 'd':
                return 13;
            case 'E':
            case 'e':
                return 14;
            case 'F':
            case 'f':
                return 15;
            case 'X':
            case 'x':
                return 0;
            case ' ':
            case '	':
                return 0;
        }
    }
    else
    {
        switch (data)
        {
            case '0':
                return 0;
            case '1':
                return 1;
            case '2':
                return 2;
            case '3':
                return 3;
            case '4':
                return 4;
            case '5':
                return 5;
            case '6':
                return 6;
            case '7':
                return 7;
            case '8':
                return 8;
            case '9':
                return 9;
            case ' ':
            case '	':
            case '-':
                return 0;
        }
    }
    return 32;
}

/*******************************/
/* CStringToInt                */
/*******************************/
extern _ARMABI double pow(double /*x*/, double /*y*/);
int CStringToInt(char *data, uint8_t nLen)
{
    uint8_t bin[12] = {0,};
    int m_nDEC = 0;
    double unit_value = 10;
    int mode = 0;
    int neg_flag = 0;

    //uint8_t str;

    if (nLen > 10)
        return -1;

    if ( (data[1] =='x' ) || (data[1] == 'X') )
    {
        mode = 0;
    }
    else
    {
        mode = 1;
        if (data[0] =='-')
            neg_flag = 1;
    }


    for (int i=0 ; i<nLen ; i++)
    {
        bin[i] = CharToInt(data[(nLen-1) - i], mode);
        if (/*bin[i] >= 0 && */bin[i] <= 15)
        {
            // 0 ~ A ~ F

            if (mode == 0)
                m_nDEC += bin[i] << (4*i);     // hex
            else
                m_nDEC += bin[i]*(unsigned int)pow(unit_value,i);//dec
        }
        else if (bin[i] == 32)
        {
            return -1;
        }
    }

    if ((mode ==1)&&(neg_flag==1))
        m_nDEC = m_nDEC*-1;

    return m_nDEC;
}

/*******************************/
/* SPD2010_MGD_Parse           */
/*******************************/
int SPD2010_MGD_Parse(void)
{
    //uint8_t return_value = 1;

    //int byte_cnt = 0;
    int i, k;
    //int byte_index = 0;
    char charValue[20] = {0,0,0,0,0,0,0,0,0,0};

    char file_data[100];
    //int file_string_length;

    int file_temp;
    //char temp_buf[10];
    int file_read_index = 0;//.. 0 : idle, 1 : part information, 2 : data
    int partinfo_linecnt = 0;

    //int mergeinfo_index = 0;
    int fw_part_index = 0;
    int file_size = sizeof(mgd_SPD2010_hex);

    //uint32_t MergeInfoBuf[20];

    for (k=0; k<file_size; k++)
    {
        //.. get line
        for (i=0; i<100; i++)
        {
            file_data[i] = mgd_SPD2010_hex[k+i];
            if (mgd_SPD2010_hex[k+i] == '\n')
            {
                break;
            }
        }


        //==============================================
        //search '$' - MergeFW Header information
        //==============================================
        if ((file_data[0] == '$')&&(file_read_index==0))
        {

            k += i;
            file_read_index = 0;
            partinfo_linecnt = 0;
            for (uint32_t idx=0; idx < sizeof(charValue); idx++)
            {
                charValue[idx] = 0x00;
            }

            charValue[0] = '0';
            charValue[1] = 'x';

            for (i=0; i<8; i++)
            {
                charValue[i+2] = file_data[i+1];
            }

            //MergeInfoBuf[mergeinfo_index++] = CStringToInt(charValue, 10);
        }
        //==============================================
        //search '#' - New FW Part
        //==============================================
        else if ((file_data[0] == '#')&&(file_read_index==0))
        {
            k += i;
            file_read_index = 1;
            partinfo_linecnt = 0;

            for (uint32_t idx=0; idx < sizeof(charValue); idx++)
            {
                charValue[idx] = 0x00;
            }

            charValue[0] = '0';
            charValue[1] = 'x';
            for (i=0; i<8; i++)
            {
                charValue[i+2] = file_data[i+1];
            }

            FW_Part[ fw_part_index ].write_address = CStringToInt(charValue, 10);
        }
        //==============================================
        //search '*' - Part Information
        //==============================================
        else if ((file_data[0] == '*')&&(file_read_index==1))
        {
            k += i;

            for (uint32_t idx=0; idx < sizeof(charValue); idx++)
            {
                charValue[idx] = 0x00;
            }
            charValue[0] = '0';
            charValue[1] = 'x';
            for (i=0; i<8; i++)
            {
                charValue[i+2] = file_data[i+1];
            }

            file_temp = CStringToInt(charValue, 10);
            switch (partinfo_linecnt)
            {
                case 0://.. length : ByteCnt
                    FW_Part[ fw_part_index ].byte_cnt = file_temp;
                    break;
                case 1://..
                    FW_Part[ fw_part_index ].erase_cnt = file_temp;
                    break;
                case 2://..
                    FW_Part[ fw_part_index ].version = file_temp;
                    break;
                case 3://..
                    FW_Part[ fw_part_index ].check_sum = file_temp;
                    break;
                case 4:
                    FW_Part[ fw_part_index ].rsvd01 = file_temp;
                    break;
                case 5:
                    FW_Part[ fw_part_index ].rsvd02 = file_temp;
                    break;
                case 6:
                    FW_Part[ fw_part_index ].rsvd03 = file_temp;
                    break;
                default :
                    break;
            }
            partinfo_linecnt++;
            if (partinfo_linecnt == 7)
                file_read_index = 2;
        }
        else
        {
            file_read_index = 0;
        }

        //..get fw part data
        if ((file_read_index == 2)&&(partinfo_linecnt ==7))
        {
            k++;
#if 0
            for (i=0; i<FW_Part[ fw_part_index ].byte_cnt; i++)
            {

                FW_Part[ fw_part_index ].content[i] = mgd_SPD2010_hex[k+i];

            }
#endif
            k += FW_Part[ fw_part_index ].byte_cnt;
            k--;
            file_read_index = 0;
            fw_part_index++;
        }

        for (uint32_t idx=0; idx < sizeof(file_data); idx++)
        {
            file_data[idx] = 0x00;
        }
    }

    FWInfo.FW_Offset[0] = (MGD_HEADER  + FW_PARTINFO);
    FWInfo.FW_Offset[1] = FWInfo.FW_Offset[0] + FW_PARTINFO + FW_Part[0].byte_cnt + MGD_NEWLINE;
    FWInfo.FW_Offset[2] = FWInfo.FW_Offset[1] + FW_PARTINFO + FW_Part[1].byte_cnt + MGD_NEWLINE;
    FWInfo.FW_Offset[3] = FWInfo.FW_Offset[2] + FW_PARTINFO + FW_Part[2].byte_cnt + MGD_NEWLINE;
    FWInfo.FW_Offset[4] = FWInfo.FW_Offset[3] + FW_PARTINFO + FW_Part[3].byte_cnt + MGD_NEWLINE;
    FWInfo.FW_Offset[5] = FWInfo.FW_Offset[4] + FW_PARTINFO + FW_Part[4].byte_cnt + MGD_NEWLINE;

    FWInfo.total_part_num = fw_part_index;

    for (uint8_t idx = 0; idx < fw_part_index; idx++)
    {
        FWInfo.order[idx] = idx;
    }

    for (uint8_t i = 0; i < FWInfo.total_part_num; i++)
    {
        for (uint8_t j = 0; j < i; j++)
        {
            if (FW_Part[j].write_address > FW_Part[i].write_address)
            {
                uint8_t temp = FWInfo.order[j];
                FWInfo.order[j] = FWInfo.order[i];
                FWInfo.order[i] = temp;
            }
        }
    }

    for (uint8_t idx = 0; idx < fw_part_index; idx++)
    {
        LOG2("[TP]:FW[%d].Offset = 0x%08x\n", idx, FWInfo.FW_Offset[idx]);
        NRF_LOG_PROCESS();
        LOG2("[TP]:FW[%d].Order = 0x%02x\n", idx, FWInfo.order[idx]);
        NRF_LOG_PROCESS();
    }

    return 0;
}
